package model;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.Pair;

import model.components.Link;
import model.components.Node;
import model.components.RequestRouter;
import model.components.RequestSwitch;
import model.components.Server;
import model.components.SubstrateRouter;
import model.components.SubstrateSwitch;
import model.components.VirtualMachine;

public class ResourceMapping {
	
	private LinkedHashMap<Node, Node> nodeMap = null; //request-real 
	private double[][][] flows;
	private boolean denied = false;

	public void setNodeMapping(LinkedHashMap<Node, Node> map){
		this.nodeMap=map;
	}
	
	public void setLinkMapping(double[][][] f){
		this.flows=f;
	}
	
	public void denied() { this.denied=true; }
	public void accepted() { this.denied=false; }
	
	public boolean isDenied() { return this.denied;}
	
	public void reserveNodes(Graph<Node, Link> sub){
		Collection<Node> v = sub.getVertices();
		Iterator<Node> itr_sub = v.iterator();
		while(itr_sub.hasNext()){
			Node subNode = (Node) itr_sub.next();
			int aug_ID = subNode.getId();

			Collection<Entry<Node, Node>> c = this.nodeMap.entrySet();
			Iterator<Entry<Node, Node>> itr = c.iterator();

			while(itr.hasNext()){
				Entry<Node, Node> entry = itr.next();
				if(aug_ID == ((Node)entry.getValue()).getId()) {
				 	if (((Node)entry.getKey()) instanceof VirtualMachine)  {
				    	 ((Server)subNode).setCpu( ((Server)entry.getValue()).getCpu()-((VirtualMachine)entry.getKey()).getCpu());
				    	 ((Server)subNode).setMemory( ((Server)entry.getValue()).getMemory()-((VirtualMachine)entry.getKey()).getMemory());
				    	 ((Server)subNode).setDiskSpace( ((Server)entry.getValue()).getDiskSpace()-((VirtualMachine)entry.getKey()).getDiskSpace());
			   	 	}
				    else if ((((Node)entry.getKey()) instanceof RequestRouter)){
				    	((SubstrateRouter)subNode).setCpu( ((SubstrateRouter)entry.getValue()).getCpu()-((RequestRouter)entry.getKey()).getCpu());
				    	((SubstrateRouter)subNode).setMemory( ((SubstrateRouter)entry.getValue()).getMemory()-((RequestRouter)entry.getKey()).getMemory());
				    }
				    else if ((((Node)entry.getKey()) instanceof RequestSwitch)) {
				    	((SubstrateSwitch)subNode).setCpu( ((SubstrateSwitch)entry.getValue()).getCpu()-((RequestSwitch)entry.getKey()).getCpu());
				    	((SubstrateSwitch)subNode).setMemory( ((SubstrateSwitch)entry.getValue()).getMemory()-((RequestSwitch)entry.getKey()).getMemory());
				    }
				}
			}
		
		}

	}
	
	/*public void releaseNodes(Substrate sub){
		Collection v = sub.getGraph().getVertices();
		Iterator itr_sub = v.iterator();
		while(itr_sub.hasNext()){
			Node subNode =  (Node) itr_sub.next();
			int aug_ID=  subNode.getId();
			//if (this.aug==1)  aug_ID += this.request.getGraph().getVertexCount();
			if(this.nodeMap!=null) {
				Collection c = this.nodeMap.entrySet();
				Iterator itr = c.iterator();
	
				while(itr.hasNext()){
					 Map.Entry entry = (Map.Entry)itr.next();
					 if(aug_ID == ((Node)entry.getValue()).getId()) {
					 	if (((Node)entry.getKey()) instanceof VirtualMachine  )  {
					    	 ((Server)subNode).setCpu( ((Server)subNode).getCpu()+((VirtualMachine)entry.getKey()).getCpu());
					    	 ((Server)subNode).setMemory( ((Server)subNode).getMemory()+((VirtualMachine)entry.getKey()).getMemory());
					    	 ((Server)subNode).setDiskSpace( ((Server)subNode).getDiskSpace()+((VirtualMachine)entry.getKey()).getDiskSpace());
				   	 	}
					    else if ((((Node)entry.getKey()) instanceof RequestRouter) ){
					    	((SubstrateRouter)subNode).setCpu( ((SubstrateRouter)subNode).getCpu()+((RequestRouter)entry.getKey()).getCpu());
					    	((SubstrateRouter)subNode).setMemory( ((SubstrateRouter)subNode).getMemory()+((RequestRouter)entry.getKey()).getMemory());
					    	 	}
					    else if ((((Node)entry.getKey()) instanceof RequestSwitch) ) {
					    	((SubstrateSwitch)subNode).setCpu( ((SubstrateSwitch)subNode).getCpu()+((RequestSwitch)entry.getKey()).getCpu());
					    	((SubstrateSwitch)subNode).setMemory( ((SubstrateSwitch)subNode).getMemory()+((RequestSwitch)entry.getKey()).getMemory());
					    	 	}
					 }
				}
			}
		}

	}*/
	
	public void reserveLinks(Graph<Node, Link> sub){
		for (int k=0;k<this.flows.length;k++){
			for (int i=0;i<sub.getVertexCount();i++){
				for (int j=0;j<sub.getVertexCount();j++){
					if (this.flows[k][i][j]!=0){
						Collection<Link> edges = sub.getEdges();
						//System.out.println("it is here");
						for (Link current : edges){
							Pair<Node> currentNodes =sub.getEndpoints(current);
							int node1 = currentNodes.getFirst().getId();
							int node2= currentNodes.getSecond().getId();
								if ( ( (node1==i)&&(node2==j)) || ( (node1==j)&&(node2==i)) ) {
									current.setBandwidth(current.getBandwidth()-((int)this.flows[k][i][j]));
								}
						}

					}
				}
			}
		}
		
	}
	
	public void reserveLinks(Substrate sub, double[][][] flows){
		
		for (int k=0;k<flows.length;k++){
			for (int i=0;i<sub.getGraph().getVertexCount();i++){
				for (int j=0;j<sub.getGraph().getVertexCount();j++){
					if (flows[k][i][j]!=0){
						Collection<Link> edges = sub.getGraph().getEdges();
						for (Link current : edges){
							Pair<Node> currentNodes =sub.getGraph().getEndpoints(current);
							int node1 = currentNodes.getFirst().getId();
							int node2= currentNodes.getSecond().getId();
								if ( ( (node1==i)&&(node2==j)) || ( (node1==j)&&(node2==i)) )
									current.setBandwidth(current.getBandwidth()-((int)this.flows[k][i][j]));
							
						}

					}
				}
			}
		}
		
	}
	
	
	public void releaseLinks(Substrate sub){
		if(this.nodeMap!=null) {
			for (int k=0;k<this.flows.length;k++){
				for (int i=0;i<sub.getGraph().getVertexCount();i++){
					for (int j=0;j<sub.getGraph().getVertexCount();j++){
						if (this.flows[k][i][j]!=0){
							Collection<Link> edges = sub.getGraph().getEdges();
							for (Link current : edges){
								Pair<Node> currentNodes =sub.getGraph().getEndpoints(current);
								int node1 = currentNodes.getFirst().getId();
								int node2= currentNodes.getSecond().getId();
									if ( ( (node1==i)&&(node2==j)) || ( (node1==j)&&(node2==i)) )
										current.setBandwidth(current.getBandwidth()+((int)this.flows[k][i][j]));
								
							}
	
						}
					}
				}
			}
		}
	}
	
	void printNodeMapping(){
		Collection c = this.nodeMap.entrySet();
		Iterator itr = c.iterator();
		while(itr.hasNext()){
			 Map.Entry entry = (Map.Entry)itr.next();
			 
			 System.out.println("Virtual " +((Node)entry.getKey()).getId()+  " cpu  " +((Node)entry.getKey()).getCpu() + 
					 " Real " + ((Node) entry.getValue()).getId() + " cpu "  + ((Node) entry.getValue()).getCpu());
		}
	}

	void printLinkMapping(Substrate sub){
		for (int k=0;k<this.flows.length;k++){
			System.out.println("For Virtual link " + k );
			for (int i=0;i<sub.getGraph().getVertexCount();i++){
				for (int j=0;j<sub.getGraph().getVertexCount();j++){
					if (this.flows[k][i][j]!=0){
						Collection<Link> edges = sub.getGraph().getEdges();
						for (Link current : edges){
							Pair<Node> currentNodes =sub.getGraph().getEndpoints(current);
							int node1 = currentNodes.getFirst().getId();
							int node2= currentNodes.getSecond().getId();
								if ( ( (node1==i)&&(node2==j)) || ( (node1==j)&&(node2==i)) )
									 System.out.println("START "+ node1+ " end " +node2+ " flow " +  
											 this.flows[k][i][j] +  " mapped tp Real " + 
											 current.getId() + " with bw " +current.getBandwidth());
						}
					}
				}
			}
		}
	}
	
}


